﻿module System.Extensibility.Data.SqlServerModel.Kilimanjaro.Smo
open System
open Microsoft.SqlServer.Management
open System.Extensibility.Data.SqlServerModel.Kilimanjaro
open fs
open Base
open Option
module Type=
    type t=Smo.SqlDataType
    let parse(a:Smo.DataType)=
        match a.SqlDataType with
            |t.Bit->Bit():>Type
            |t.TinyInt->TinyInt():>Type
            |t.SmallInt->SmallInt():>Type
            |t.Int->Int():>Type
            |t.Money->Money():>Type
            |t.DateTime->DateTime():>Type
            |t.Date->Date():>Type
            |t.Time->Time():>Type
            |t.UniqueIdentifier->UniqueIdentifier():>Type
            |t.Decimal->Decimal(a.NumericPrecision,a.NumericScale):>Type
            |t.Char->Char a.MaximumLength:>Type
            |t.NChar->NChar a.MaximumLength:>Type
            |t.VarChar->VarChar a.MaximumLength:>Type
            |t.NVarChar->NVarChar a.MaximumLength:>Type
            |t.NVarCharMax->NVarChar a.MaximumLength:>Type
            |t.VarBinaryMax->VarBinary a.MaximumLength:>Type
            |t.Xml->Xml():>Type
            |t.NText->NText():>Type
            |t.Text->Text():>Type
            |t.Image->Image():>Type
            |t.SysName->Image():>Type
            |t.HierarchyId->NotSupported():>Type
            |t.UserDefinedDataType->NotSupported():>Type
            |_->NotSupported():>Type
//            | _ -> raise (NotSupportedException(sprintf "%A" a.SqlDataType))
module Server=
    let databases=
        let column(a:Smo.Column)=
            if a.Identity then IdentityColumn a.Name:>Column elif a.RowGuidCol then RowGuidColumn a.Name:>Column
                elif a.Name.Equals("ModifiedDate",StringComparison.OrdinalIgnoreCase)then ModifiedDateColumn():>Column
                else Column(a.Name,Type.parse a.DataType,a.Identity,a.Nullable)
        let table(a:Smo.Table)=
            let columns=a.Columns|>Seq.cast<Smo.Column>|>Seq.map(fun a -> column a)
            let id=columns|>Seq.ofType<IdentityColumn>|>fromSeq
            let g=columns|>Seq.ofType<RowGuidColumn>|>fromSeq
            let p=
                let n=a.Indexes|>Seq.cast<Smo.Index>|>Seq.find(fun a->a.IndexKeyType=Smo.IndexKeyType.DriPrimaryKey)|>fun a->a.IndexedColumns|>Seq.cast<Smo.IndexedColumn>|>Seq.map(fun a->a.Name)
                columns|>Seq.filter(fun a->n|>Seq.exists(fun b->b=a.Name))
            Table(a.Name,columns,Schema.create a.Schema,id,g,p,Seq.empty)
        let database(a:Smo.Database)=
            let s=a.Schemas|>Seq.cast<Smo.Schema>|>Seq.map(fun a->Schema.create a.Name)
            Database(a.Name,a.Tables|>Seq.cast<Smo.Table>|>Seq.map(fun a->table a),s)
        let s=Smo.Server()
        s.Databases|>Seq.cast<Smo.Database>|>Seq.map(fun a->database a)
    module Test=
        let adventureWorks _=
            let d=databases|>Seq.find(fun a->a.Name="AdventureWorks2008R2")
            assert d.Name.Equals"AdventureWorks2008R2"
            assert(d.Schemas|>Seq.map(fun a->a.Name)|>String.concat","|>fun a->a.Equals"db_accessadmin,db_backupoperator,db_datareader,db_datawriter,db_ddladmin,db_denydatareader,db_denydatawriter,db_owner,db_securityadmin,dbo,guest,HumanResources,INFORMATION_SCHEMA,Person,Production,Purchasing,Sales,sys")